#include "PlayerEvent.h"
#include "Log.h"
#include "BedWars.h"
#include "GameRegistry.hpp"
#include "Player/PlayerData.h"
#include "Components/ComponentBody.h"
#include "Components/ComponentPlayer.h"
#include "Components/ComponentAttacker.h"
#include "Components/ComponentMiner.h"
#include "Components/ComponentOnFire.h"

#include "SubsystemBedWars.h"
#include "Network/PackageManager.h"
#include "Network/Packages/MessagePackage.h"
#include "Components/ComponentHealth.h"
#include "Subsystems/SubsystemTerrain.h"
#include "Blocks/CairnBlock.h"
#include "Blocks/DiamondBlock.h"
#include "Blocks/MatchBlock.h"
#include "Game/BodyRaycastResult.hpp"

namespace BedWars
{

    static void sendMessage(ClientPtr client, const std::string & message)
    {
        std::shared_ptr<MessagePackage> package = std::make_shared<MessagePackage>(message);
        package->client = client;
        package->sendType = PackageSendType::TARGET;
        GameSingleton::packageManager->addSendPackageToQueue(package);
    }

    bool PlayerEvent::cmdFrontMessage(std::shared_ptr<PlayerData> playerData, std::string &message, std::vector<uint8_t> &toClients)
    {
        TeamType teamType = m_bedWarsCore->subsystemBedWars->getEntityTeam(playerData->entity);
        if(message[0] == '/' && teamType != TeamType::None)
        {
            if(message == "/exit")
            {
                m_bedWarsCore->subsystemBedWars->resetPlayer(playerData->componentPlayer);
                m_bedWarsCore->subsystemBedWars->exitTeam(playerData->entity);
                playerData->componentPlayer->setNetPosition(m_bedWarsCore->respawnPosition);

                sendMessage(playerData->client, "退出成功");
                return false;
            }
            else if(message == "/bed")
            {
                sendMessage(playerData->client, fmt::format("剩余人数: 红队:{} 蓝队:{} 绿队:{} 紫队:{}", 
                    m_bedWarsCore->subsystemBedWars->teamEntitySet[0].size(),
                    m_bedWarsCore->subsystemBedWars->teamEntitySet[1].size(),
                    m_bedWarsCore->subsystemBedWars->teamEntitySet[2].size(),
                    m_bedWarsCore->subsystemBedWars->teamEntitySet[3].size()
                ));
                return false;
            }
            sendMessage(playerData->client, "\n你已经参加了游戏，不能发送其它指令，你可以发送 /exit 退出游戏");
            return false;
        }
        int32_t num = 0;
        for(int32_t index = 0; index < message.length(); ++index)
        {
            if(message[index] == '\n')
            {
                ++num;
                if(num > 8)
                {
                    return false;
                }
            }
        }
        return true;
    }

    bool PlayerEvent::playerMove(std::shared_ptr<PlayerData> playerData, const Vector3 &position)
    {
        // if(m_bedWarsCore->isEditMode == false)
        // {
        //     switch (m_bedWarsCore->subsystemBedWars->mainStatue)
        //     {
        //     case BedWarsStatue::Prepare:
        //         if(position.posY < m_bedWarsCore->limitHeight)
        //         {
        //             playerData->componentPlayer->setNetPosition(m_bedWarsCore->respawnPosition);
        //         }
        //         break;
        //     case BedWarsStatue::Countdown:
        //         break;
        //     case BedWarsStatue::GameRunning:
        //     case BedWarsStatue::Ending:
        //         {
        //             TeamType ranksType = m_bedWarsCore->subsystemBedWars->getEntityTeam(playerData->entity);
        //             if(ranksType == TeamType::None)
        //             {
        //                 if(position.posY < m_bedWarsCore->limitHeight)
        //                 {
        //                     playerData->componentPlayer->setNetPosition(m_bedWarsCore->respawnPosition);
        //                 }
        //             }
        //             else
        //             {
        //                 if(position.posY < 0.0f)
        //                 {
        //                     // playerData->componentPlayer->setNetPosition(m_bedWarsCore->respawnPosition);
        //                     playerData->componentPlayer->componentHealth->injure(999.0f, entt::null, true, "越界被处死", InjureType::Plugin);
        //                 }
        //                 else if(position.posY >= m_bedWarsCore->limitHeight + 3)
        //                 {
        //                     playerData->componentPlayer->componentHealth->injure(0.1f, entt::null, true, "越界被处死", InjureType::Unknow);
        //                 }
        //             }
        //         }
        //         break;
        //     }
        // }
        return true;
    }

    bool PlayerEvent::playerPlaceBlock(ComponentPlayer *componentPlayer, const Point3 &point, int32_t placeBlockValue)
    {
        SubsystemTerrain *subsystemTerrain = GameSingleton::singletonPtr->getSingleton<SubsystemTerrain>();
        int32_t blockContent = Terrain::ExtractContents(placeBlockValue);
        if(m_bedWarsCore->isEditMode == false)
        {
            if(m_bedWarsCore->subsystemBedWars->mainStatue != BedWarsStatue::GameRunning || 
                point.posY >= (m_bedWarsCore->limitHeight - 20) || 
                blockContent == 45 || 
                blockContent == 64 || 
                blockContent == 27)
            {
                return false;
            }
            int32_t targetCellContent = subsystemTerrain->getCellContents(point);
            if (targetCellContent == 45 ||                      // 箱子
                targetCellContent == CairnBlock::Index() ||     // 十字坟碑
                targetCellContent == DiamondBlock::Index() ||   // 钻石块
                targetCellContent == 46 ||                      // 铁块
                targetCellContent == 47)                        // 铜块
            {
                return false;   
            }
            int32_t bottomCellContent = subsystemTerrain->getCellContents(point.posX, point.posY - 1, point.posZ);
            if (bottomCellContent == DiamondBlock::Index() ||
                bottomCellContent == 46 ||
                bottomCellContent == 47)
            {
                return false;
            }
            for(uint8_t index = 0; index < 4; index++)
            {
                Vector3 pos = m_bedWarsCore->teamData[index].startPosition - point;
                if(pos.length() < 4)
                {
                    return false;
                }
            }
        }
        else
        {
            if (placeBlockValue == DiamondBlock::Index() ||
                placeBlockValue == 46 ||
                placeBlockValue == 47)
            {
                m_bedWarsCore->addResourcePoint(point);

                sendMessage(componentPlayer->playerData->client, "成功添加资源点");
            }
            else if(placeBlockValue == CairnBlock::Index())
            {
                TeamType teamType = m_bedWarsCore->getSetTeamHomeType(componentPlayer->entity);
                if(teamType != TeamType::None)
                {
                    const std::string &teamName = m_bedWarsCore->subsystemBedWars->getTeamName(teamType);

                    m_bedWarsCore->teamData[(uint8_t)teamType].bedPoint = point;

                    sendMessage(componentPlayer->playerData->client, fmt::format("成功设置 {} 的坟碑点为 {},{},{}", teamName, point.posX, point.posY, point.posZ));
                }
            }
        }
        return true;
    }

    bool PlayerEvent::playerBreakBlock(ComponentPlayer *componentPlayer, const Point3 &point, int32_t digBlockValue, int32_t toolLevel)
    {
        if(m_bedWarsCore->isEditMode == false)
        {
            if(m_bedWarsCore->subsystemBedWars->mainStatue == BedWarsStatue::GameRunning)
            {
                if(point.posY >= m_bedWarsCore->limitHeight)
                {
                    return false;
                }
                int32_t cellContent = Terrain::ExtractContents(digBlockValue);
                if (cellContent == 45 ||                      // 箱子
                    cellContent == DiamondBlock::Index() ||   // 钻石块
                    cellContent == 46 ||                      // 铁块
                    cellContent == 47)                        // 铜块
                {
                    return false;   
                }
                for(uint8_t index = 0; index < 4; index++)
                {
                    Vector3 pos = m_bedWarsCore->teamData[index].startPosition - point;
                    if(pos.length() < 4)
                    {
                        return false;
                    }
                }

                if(cellContent == CairnBlock::Index())
                {
                    TeamType carinTeamType = TeamType::None;
                    for(uint8_t index = 0; index < 4; ++index)
                    {
                        if(m_bedWarsCore->teamData[index].bedPoint == point)
                        {
                            carinTeamType = (TeamType)index;
                        }
                    }
                    TeamType breakerTeamType = m_bedWarsCore->subsystemBedWars->getEntityTeam(componentPlayer->entity);
                    if(carinTeamType == TeamType::None || breakerTeamType == TeamType::None)
                    {
                        return false;
                    }
                    if(carinTeamType == breakerTeamType)
                    {
                        sendMessage(componentPlayer->playerData->client, "你不能破坏自家的坟碑");
                        return false;
                    }
                    uint8_t teamHealth = m_bedWarsCore->subsystemBedWars->decTeamHealth(carinTeamType);
                    // 墓碑的血量还有，那么就不能被破坏掉
                    if(teamHealth != 0)
                    {
                        sendMessage(componentPlayer->playerData->client, fmt::format("坟碑还需破坏 {} 次", teamHealth));
                        return false;
                    }
                    const std::string &teamName = m_bedWarsCore->subsystemBedWars->getTeamName(carinTeamType);
                    const std::string &breakerTeamName = m_bedWarsCore->subsystemBedWars->getTeamName(breakerTeamType);
                    GameSingleton::packageManager->addSendPackageToQueue(std::make_shared<MessagePackage>(
                        "",
                        fmt::format("{} 的坟碑被 {} 的 {} 拆掉了", teamName, breakerTeamName, componentPlayer->playerData->username),
                        6.0f, 
                        0.0f));
                    m_bedWarsCore->subsystemBedWars->teamZeroPlayerClear(carinTeamType);
                }
                return true;
            }
            return false;
        }
        else
        {
            if (digBlockValue == DiamondBlock::Index() ||
                digBlockValue == 46 ||
                digBlockValue == 47)
            {
                m_bedWarsCore->removeResourcePoint(point);
                sendMessage(componentPlayer->playerData->client, "移除资源点");
            }
        }
        return true;
    }

    // 玩家重生
    void PlayerEvent::playerRestart(ComponentPlayer* componentPlayer)
    {
        if(m_bedWarsCore->isEditMode == false)
        {
            TeamType teamType = m_bedWarsCore->subsystemBedWars->getEntityTeam(componentPlayer->entity);
            if(teamType != TeamType::None)
            {
                if(m_bedWarsCore->subsystemBedWars->getTeamHealth(teamType) == 0 || m_bedWarsCore->subsystemBedWars->canRestart == false)
                {
                    m_bedWarsCore->subsystemBedWars->resetPlayer(componentPlayer);
                    m_bedWarsCore->subsystemBedWars->exitTeam(componentPlayer->entity);
                }
                else
                {
                    m_bedWarsCore->subsystemBedWars->setTeamClothes(componentPlayer, teamType);
                    m_bedWarsCore->subsystemBedWars->addBaseTools(componentPlayer);
                }
                componentPlayer->componentHealth->invincibleTime = 10.0f;
            }
            componentPlayer->componentBody->setVelocity(FastVector3::Zero);
            // 非编辑模式的话，队伍要传送到队伍的出生点，没有队伍要传送到大厅
            m_bedWarsCore->subsystemBedWars->toTeamHomePosition(componentPlayer);
        }
    }

    bool PlayerEvent::onUse(ComponentMiner *componentMiner, const Ray3& ray)
    {
        if(componentMiner->getActiveBlockValue() == MatchBlock::Index())
        {
            RaycastData raycastData = componentMiner->raycast(ray, RaycastMode::Digging);
            if(raycastData.bodyRaycastResult != nullptr)
            {
                ComponentOnFire **componentOnFirePtr =  GameSingleton::gameRegistry->try_get<ComponentOnFire*>(raycastData.bodyRaycastResult->componentBody->entity);
                if(componentOnFirePtr != nullptr)
                {
                    ComponentOnFire *onFire = *componentOnFirePtr;
                    TeamType minerTeam = m_bedWarsCore->subsystemBedWars->getEntityTeam(componentMiner->entity);
                    TeamType beFireTeam = m_bedWarsCore->subsystemBedWars->getEntityTeam(onFire->entity);
                    if(minerTeam == beFireTeam || minerTeam == TeamType::None || beFireTeam == TeamType::None)
                    {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    bool PlayerEvent::hitBody(ComponentAttacker* attacker, ComponentBody *body, const Vector3 &hitPosition, const Vector3 &hitDirection)
    {
        if(m_bedWarsCore->isEditMode == false)
        {
            if(m_bedWarsCore->subsystemBedWars->mainStatue == BedWarsStatue::GameRunning)
            {
                if(attacker->entity == body->entity)
                {
                    return true;
                }
                TeamType attackerTeam = m_bedWarsCore->subsystemBedWars->getEntityTeam(attacker->entity);
                TeamType beAttacketTeam = m_bedWarsCore->subsystemBedWars->getEntityTeam(body->entity);
                if(attackerTeam != beAttacketTeam && beAttacketTeam != TeamType::None && attackerTeam != TeamType::None)
                {
                    return true;
                }
            }
            return false;
        }
        return true;
    }

    bool PlayerEvent::injureEntity(ComponentHealth *health, float amount, entt::entity attackerEntity, bool realInjure, const std::string &cause, InjureType injureType)
    {
        if(m_bedWarsCore->isEditMode == false)
        {
            if(m_bedWarsCore->subsystemBedWars->mainStatue == BedWarsStatue::GameRunning)
            {
                TeamType teamType = m_bedWarsCore->subsystemBedWars->getEntityTeam(health->entity);
                if(attackerEntity != entt::null && health->entity != attackerEntity)
                {
                    TeamType attackerTeam = m_bedWarsCore->subsystemBedWars->getEntityTeam(attackerEntity);
                    if(teamType == attackerTeam && attackerTeam != TeamType::None)
                    {
                        return false;
                    }
                }

                if(teamType != TeamType::None)
                {
                    if(health->invincibleTime > 0 && attackerEntity != entt::null && injureType == InjureType::BeAttacked)
                    {
                        ComponentHealth *componentHealth = GameSingleton::gameRegistry->get<ComponentHealth*>(attackerEntity);
                        componentHealth->injure(amount / 2.5f, entt::null, false, "被无敌反甲刺死");
                    }
                    return true;
                }
            }
            return false;
        }
        return true;
    }

    bool PlayerEvent::entityDeath(ComponentHealth *health, float amount, entt::entity attackerEntity, const std::string &cause)
    {
        if(m_bedWarsCore->isEditMode == false)
        {
            ComponentPlayer **componentPlayerPtr = GameSingleton::gameRegistry->try_get<ComponentPlayer*>(health->entity);
            if(componentPlayerPtr != nullptr)
            {
                ComponentPlayer *componentPlayer = *componentPlayerPtr;
                TeamType teamType = m_bedWarsCore->subsystemBedWars->getEntityTeam(componentPlayer->entity);
                if(teamType != TeamType::None)
                {
                    if(m_bedWarsCore->subsystemBedWars->getTeamHealth(teamType) == 0 || m_bedWarsCore->subsystemBedWars->canRestart == false)
                    {
                        m_bedWarsCore->subsystemBedWars->exitTeam(componentPlayer->entity);
                    }
                }
            }
        }
        return true;
    }

} // namespace BedWars
